package com.bsj.travel.system.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsj.travel.def.common.DO.MenuDO;
import com.bsj.travel.def.common.DO.RoleDO;
import com.bsj.travel.def.common.DO.RoleMenuDO;
import com.bsj.travel.def.common.DTO.web.menu.MenuDTO;
import com.bsj.travel.def.common.DTO.web.menu.MenuSearchDTO;
import com.bsj.travel.def.common.VO.MenuTreeVO;
import com.bsj.travel.def.common.VO.MenuVO;
import com.bsj.travel.def.global.JsonResult;
import com.bsj.travel.def.global.JsonResultEnum;
import com.bsj.travel.exception.ApiException;
import com.bsj.travel.mapper.mysql.MenuMapper;
import com.bsj.travel.mapper.mysql.RoleMapper;
import com.bsj.travel.mapper.mysql.RoleMenuMapper;
import com.bsj.travel.security.service.TokenService;
import com.bsj.travel.def.common.VO.TokenUser;
import com.bsj.travel.system.service.MenuService;
import com.bsj.travel.util.SecurityUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/***
 * @description MenuServiceImpl
 * @author LiJiaXin
 * @version 1.0.0
 * @time 2024/1/12 16:36
 **/
@Service
public class MenuServiceImpl implements MenuService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private TokenService tokenService;

    /**
     * 添加权限
     *
     * @param menuDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/12 16:38
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult addMenu(MenuDTO menuDTO) {
        paramCheck(menuDTO);
        MenuDO menuDO = new MenuDO();
        BeanUtils.copyProperties(menuDTO, menuDO);
        if (menuMapper.insert(menuDO) > 0) {
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 参数校验
     *
     * @param menuDTO
     * @return void
     * @author ljx
     * @time 2024/1/12 17:01
     */
    private void paramCheck(MenuDTO menuDTO) {
        //去重校验
        MenuSearchDTO menuSearchDTO = new MenuSearchDTO();
        menuSearchDTO.setId(menuDTO.getId());
        menuSearchDTO.setMenuName(menuDTO.getMenuName());
        if (menuMapper.countByCondition(menuSearchDTO) >= 1) {
            throw new ApiException(JsonResultEnum.MENU_NAME_IS_NOT_NULL);
        }
        menuSearchDTO.setMenuName(null);
        menuSearchDTO.setMenuSign(menuDTO.getMenuSign());
        if (menuMapper.countByCondition(menuSearchDTO) >= 1) {
            throw new ApiException(JsonResultEnum.MENU_SIGN_IS_NOT_NULL);
        }
    }

    /**
     * 删除权限
     *
     * @param id
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/12 16:38
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult deleteMenu(Integer id) {
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        if (menuMapper.selectById(id) == null) {
            return JsonResult.fail(JsonResultEnum.MENU_IS_NOT_EXIST);
        }
//        final String menuId = "menuId";
//        if (roleMenuMapper.exists(new QueryWrapper<RoleMenuDO>().eq(menuId, id))) {
//            return JsonResult.fail(JsonResultEnum.FAIL, "此权限与某角色已绑定，无法删除");
//        }
        if (menuMapper.deleteById(id) > 0) {
            //删除与角色的关系
            roleMenuMapper.delete(new QueryWrapper<RoleMenuDO>().eq("menuId", id));
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 修改权限
     *
     * @param menuDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/12 16:38
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateMenu(MenuDTO menuDTO) {
        Integer id = menuDTO.getId();
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        if (menuMapper.selectById(id) == null) {
            return JsonResult.fail(JsonResultEnum.MENU_IS_NOT_EXIST);
        }
        paramCheck(menuDTO);
        MenuDO menuDO = new MenuDO();
        BeanUtils.copyProperties(menuDTO, menuDO);
        if (menuMapper.updateById(menuDO) > 0) {
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 根据权限id获取权限信息
     *
     * @param id
     * @return com.bsj.travel.def.common.VO.MenuVO
     * @author ljx
     * @time 2024/1/12 16:39
     */
    @Override
    public MenuVO getMenuInfoById(Integer id) {
        if (id == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        MenuDO menuDO = menuMapper.selectById(id);
        if (menuDO == null) {
            throw new ApiException(JsonResultEnum.MENU_IS_NOT_EXIST);
        }
        MenuVO menuVO = new MenuVO();
        BeanUtils.copyProperties(menuDO, menuVO);
        return menuVO;
    }

    /**
     * 权限分页
     *
     * @param menuSearchDTO
     * @return com.bsj.travel.def.global.JsonResult<java.util.List < com.bsj.travel.def.common.VO.MenuVO>>
     * @author ljx
     * @time 2024/1/12 16:39
     */
    @Override
    public JsonResult<List<MenuVO>> pageMenu(MenuSearchDTO menuSearchDTO) {
        IPage<MenuDO> page = new Page<>(menuSearchDTO.getPageNumber(), menuSearchDTO.getPageSize());
        QueryWrapper<MenuDO> queryWrapper = new QueryWrapper<>();
        String menuName = menuSearchDTO.getMenuName();
        String menuSign = menuSearchDTO.getMenuSign();
        if (StringUtils.isNotBlank(menuName)) {
            queryWrapper.eq("menuName", menuName);
        }
        if (StringUtils.isNotBlank(menuSign)) {
            queryWrapper.eq("menuSign", menuSign);
        }
        IPage<MenuDO> iPage = menuMapper.selectPage(page, queryWrapper);
        List<MenuDO> menuDOS = iPage.getRecords();
        int total = (int) iPage.getTotal();
        List<MenuVO> menuVOS = new LinkedList<>();
        if (total == 0) {
            return JsonResult.success(menuVOS, total);
        }
        menuVOS = menuDOS.stream().map(menuDO -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(menuDO, menuVO);
            menuVO.setCreateTime(DateUtil.formatDateTime(menuDO.getCreateTime()));
            menuVO.setUpdateTime(DateUtil.formatDateTime(menuDO.getUpdateTime()));
            return menuVO;
        }).collect(Collectors.toList());
        return JsonResult.success(menuVOS, total);
    }

    /**
     * 获取权限树
     *
     * @return java.util.List<com.bsj.travel.def.common.VO.MenuTreeVO>
     * @author ljx
     * @time 2024/1/18 16:58
     */
    @Override
    public List<MenuTreeVO> getMenuTree() {
        TokenUser tokenUser = tokenService.getLoginUser(SecurityUtils.getToken());
        Set<String> roles = tokenUser.getRoles();
        //查询有哪些角色
        QueryWrapper<RoleDO> roleDOQueryWrapper = new QueryWrapper<>();
        roleDOQueryWrapper.in("roleSign", roles);
        roleDOQueryWrapper.select("id");
        //查询角色绑定了哪些权限
        List<RoleDO> roleDOS = roleMapper.selectList(roleDOQueryWrapper);
        QueryWrapper<RoleMenuDO> roleMenuDOQueryWrapper = new QueryWrapper<>();
        roleMenuDOQueryWrapper.select("menuId");
        roleDOQueryWrapper.in("roleId", roleDOS.stream().map(RoleDO::getId).collect(Collectors.toSet()));
        List<RoleMenuDO> roleMenuDOS = roleMenuMapper.selectList(roleMenuDOQueryWrapper);
        //查询权限信息
        QueryWrapper<MenuDO> menuDOQueryWrapper = new QueryWrapper<>();
        menuDOQueryWrapper.select("id", "menuName", "menuSign", "parentId");
        menuDOQueryWrapper.in("id", roleMenuDOS.stream().map(RoleMenuDO::getMenuId).collect(Collectors.toSet()));
        return structureErection(menuMapper.selectList(menuDOQueryWrapper));
    }

    /**
     * 树结构搭建
     *
     * @param menuDOS
     * @return java.util.List<com.bsj.travel.def.common.VO.MenuTreeVO>
     * @author ljx
     * @time 2024/1/18 17:19
     */
    @Override
    public List<MenuTreeVO> structureErection(List<MenuDO> menuDOS) {
        List<MenuTreeVO> menuTreeVOS = new LinkedList<>();
        if (CollectionUtils.isEmpty(menuDOS)) {
            return menuTreeVOS;
        }
        //类型转换
        Map<Integer, MenuTreeVO> menuTreeVOMap = menuDOS.stream().map(menuDO -> {
            MenuTreeVO tree = new MenuTreeVO();
            BeanUtils.copyProperties(menuDO, tree);
            return tree;
        }).collect(Collectors.toMap(MenuTreeVO::getId, a -> a, (k1, k2) -> k1));

        for (MenuDO menuDO : menuDOS) {
            //当前权限
            MenuTreeVO tree = menuTreeVOMap.get(menuDO.getId());
            //当前权限的父权限
            MenuTreeVO parentMenuTree = menuTreeVOMap.get(menuDO.getParentId());
            //不为空说明有上级权限
            if (parentMenuTree != null) {
                List<MenuTreeVO> children = parentMenuTree.getChildren();
                if (CollectionUtils.isEmpty(children)) {
                    List<MenuTreeVO> menuTreeVOList = new LinkedList<>();
                    menuTreeVOList.add(tree);
                    parentMenuTree.setChildren(menuTreeVOList);
                } else {
                    children.add(tree);
                }
            } else {
                //最上层权限
                menuTreeVOS.add(tree);
            }
        }
        return menuTreeVOS;
    }
}
